<!DOCTYPE html>
<html CN>







<head>
	
	
	<link rel="stylesheet" href="/css/allinone.min.css"> 

	
	<!-- Global Site Tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id=UA-42863699-1"></script>
	<script>
		window.dataLayer = window.dataLayer || [];
		function gtag(){dataLayer.push(arguments);}
		gtag('js', new Date());
		gtag('config', 'UA-42863699-1');
	</script>
	

	<meta charset="utf-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />

	<title>docker 容器网络方案：calico 网络模型 | Cizixs Write Here</title>

	<meta name="HandheldFriendly" content="True" />
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
	<meta name="generator" content="hexo">
	<meta name="author" content="Cizixs Wu">
	<meta name="description" content="">

	
	<meta name="keywords" content="">
	

	
	<link rel="shortcut icon" href="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg">
	

	
	<meta name="theme-color" content="#3c484e">
	<meta name="msapplication-TileColor" content="#3c484e">
	

	

	

	<meta property="og:site_name" content="Cizixs Write Here">
	<meta property="og:type" content="article">
	<meta property="og:title" content="docker 容器网络方案：calico 网络模型 | Cizixs Write Here">
	<meta property="og:description" content="">
	<meta property="og:url" content="http://cizixs.com/2017/10/19/docker-calico-network/">

	
	<meta property="article:published_time" content="2017-10-19T00:10:00+08:00"/> 
	<meta property="article:author" content="Cizixs Wu">
	<meta property="article:published_first" content="Cizixs Write Here, /2017/10/19/docker-calico-network/" />
	

	
	
	<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
	

	
	<script src="https://cdn.staticfile.org/highlight.js/9.10.0/highlight.min.js"></script>
	

	
	
<link rel="stylesheet" href="/css/prism-base16-ateliersulphurpool.light.css" type="text/css"></head>
<body class="post-template">
    <div class="site-wrapper">
        




<header class="site-header outer" style="z-index: 999">
    <div class="inner">
        
<nav class="site-nav"> 
    <div class="site-nav-left">
        <ul class="nav">
            <li>
                
                <a href="/" title="Home">Home</a>
                
            </li>
            
            
            <li>
                <a href="/about" title="About">About</a>
            </li>
            
            <li>
                <a href="/archives" title="Archives">Archives</a>
            </li>
            
            
        </ul> 
    </div>
    <div class="site-nav-right">
        
<div class="social-links" >
    
    <a class="social-link" title="weibo" href="https://weibo.com/1921727853" target="_blank" rel="noopener">
        <svg viewBox="0 0 1141 1024" xmlns="http://www.w3.org/2000/svg"><path d="M916.48 518.144q27.648 21.504 38.912 51.712t9.216 62.976-14.336 65.536-31.744 59.392q-34.816 48.128-78.848 81.92t-91.136 56.32-94.72 35.328-89.6 18.944-75.264 7.68-51.712 1.536-49.152-2.56-68.096-10.24-78.336-21.504-79.872-36.352-74.24-55.296-59.904-78.848q-16.384-29.696-22.016-63.488t-5.632-86.016q0-22.528 7.68-51.2t27.136-63.488 53.248-75.776 86.016-90.112q51.2-48.128 105.984-85.504t117.248-57.856q28.672-10.24 63.488-11.264t57.344 11.264q10.24 11.264 19.456 23.04t12.288 29.184q3.072 14.336 0.512 27.648t-5.632 26.624-5.12 25.6 2.048 22.528q17.408 2.048 33.792-1.536t31.744-9.216 31.232-11.776 33.28-9.216q27.648-5.12 54.784-4.608t49.152 7.68 36.352 22.016 17.408 38.4q2.048 14.336-2.048 26.624t-8.704 23.04-7.168 22.016 1.536 23.552q3.072 7.168 14.848 13.312t27.136 12.288 32.256 13.312 29.184 16.384zM658.432 836.608q26.624-16.384 53.76-45.056t44.032-64 18.944-75.776-20.48-81.408q-19.456-33.792-47.616-57.344t-62.976-37.376-74.24-19.968-80.384-6.144q-78.848 0-139.776 16.384t-105.472 43.008-72.192 60.416-38.912 68.608q-11.264 33.792-6.656 67.072t20.992 62.976 42.496 53.248 57.856 37.888q58.368 25.6 119.296 32.256t116.224 0.512 100.864-21.504 74.24-33.792zM524.288 513.024q20.48 8.192 38.912 18.432t32.768 27.648q10.24 12.288 17.92 30.72t10.752 39.424 1.536 42.496-9.728 38.912q-8.192 18.432-19.968 37.376t-28.672 35.328-40.448 29.184-57.344 18.944q-61.44 11.264-117.76-11.264t-88.064-74.752q-12.288-39.936-13.312-70.656t16.384-66.56q13.312-27.648 40.448-51.712t62.464-38.912 75.264-17.408 78.848 12.8zM361.472 764.928q37.888 3.072 57.856-18.432t21.504-48.128-15.36-47.616-52.736-16.896q-27.648 3.072-43.008 23.552t-17.408 43.52 9.728 42.496 39.424 21.504zM780.288 6.144q74.752 0 139.776 19.968t113.664 57.856 76.288 92.16 27.648 122.88q0 33.792-16.384 50.688t-35.328 17.408-35.328-14.336-16.384-45.568q0-40.96-22.528-77.824t-59.392-64.512-84.48-43.52-96.768-15.872q-31.744 0-47.104-15.36t-14.336-34.304 18.944-34.304 51.712-15.36zM780.288 169.984q95.232 0 144.384 48.64t49.152 146.944q0 30.72-10.24 43.52t-22.528 11.264-22.528-14.848-10.24-35.84q0-60.416-34.816-96.256t-93.184-35.84q-19.456 0-28.672-10.752t-9.216-23.04 9.728-23.04 28.16-10.752z" /></svg>
    </a>
    

    
    <a class="social-link" title="github" href="https://github.com/cizixs" target="_blank" rel="noopener">
        <svg viewBox="0 0 1049 1024" xmlns="http://www.w3.org/2000/svg"><path d="M524.979332 0C234.676191 0 0 234.676191 0 524.979332c0 232.068678 150.366597 428.501342 358.967656 498.035028 26.075132 5.215026 35.636014-11.299224 35.636014-25.205961 0-12.168395-0.869171-53.888607-0.869171-97.347161-146.020741 31.290159-176.441729-62.580318-176.441729-62.580318-23.467619-60.841976-58.234462-76.487055-58.234463-76.487055-47.804409-32.15933 3.476684-32.15933 3.476685-32.15933 53.019436 3.476684 80.83291 53.888607 80.83291 53.888607 46.935238 79.963739 122.553122 57.365291 152.97411 43.458554 4.345855-33.897672 18.252593-57.365291 33.028501-70.402857-116.468925-12.168395-239.022047-57.365291-239.022047-259.012982 0-57.365291 20.860106-104.300529 53.888607-140.805715-5.215026-13.037566-23.467619-66.926173 5.215027-139.067372 0 0 44.327725-13.906737 144.282399 53.888607 41.720212-11.299224 86.917108-17.383422 131.244833-17.383422s89.524621 6.084198 131.244833 17.383422C756.178839 203.386032 800.506564 217.29277 800.506564 217.29277c28.682646 72.1412 10.430053 126.029806 5.215026 139.067372 33.897672 36.505185 53.888607 83.440424 53.888607 140.805715 0 201.64769-122.553122 245.975415-239.891218 259.012982 19.121764 16.514251 35.636014 47.804409 35.636015 97.347161 0 70.402857-0.869171 126.898978-0.869172 144.282399 0 13.906737 9.560882 30.420988 35.636015 25.205961 208.601059-69.533686 358.967656-265.96635 358.967655-498.035028C1049.958663 234.676191 814.413301 0 524.979332 0z" /></svg>
    </a>
    

    
    <a class="social-link" title="stackoverflow" href="https://stackoverflow.com/users/1925083/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15 21h-10v-2h10v2zm6-11.665l-1.621-9.335-1.993.346 1.62 9.335 1.994-.346zm-5.964 6.937l-9.746-.975-.186 2.016 9.755.879.177-1.92zm.538-2.587l-9.276-2.608-.526 1.954 9.306 2.5.496-1.846zm1.204-2.413l-8.297-4.864-1.029 1.743 8.298 4.865 1.028-1.744zm1.866-1.467l-5.339-7.829-1.672 1.14 5.339 7.829 1.672-1.14zm-2.644 4.195v8h-12v-8h-2v10h16v-10h-2z"/></svg>
    </a>
    

    

    
    <a class="social-link" title="twitter" href="https://twitter.com/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"/></svg>

    </a>
    

    
    <a class="social-link" title="instagram" href="https://www.instagram.com/cizixs/" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg>
    </a>
    
    
    
</div>
    </div>
</nav>
    </div>
</header>


<main id="site-main" class="site-main outer" role="main">
    <div class="inner">
        <header class="post-full-header">
            <section class="post-full-meta">
                <time  class="post-full-meta-date" datetime="2017-10-18T16:00:00.000Z" itemprop="datePublished">
                    2017-10-19
                </time>
                
                <span class="date-divider">/</span>
                
                <a href="/categories/blog/">blog</a>&nbsp;&nbsp;
                
                
            </section>
            <h1 class="post-full-title">docker 容器网络方案：calico 网络模型</h1>
        </header>
        <article class="post-full no-image">
            
            <section class="post-full-content">
                <div id="lightgallery" class="markdown-body">
                    <h2 id="calico-简介"><a href="#calico-简介" class="headerlink" title="calico 简介"></a>calico 简介</h2><p>calico 是容器网络的又一种解决方案，和其他虚拟网络最大的不同是，它没有采用 overlay 网络做报文的转发，提供了纯 3 层的网络模型。三层通信模型表示每个容器都通过 IP 直接通信，中间通过路由转发找到对方。在这个过程中，容器所在的节点类似于传统的路由器，提供了路由查找的功能。</p>
<p>要想路由工作能够正常，每个虚拟路由器（容器所在的主机节点）必须有某种方法知道整个集群的路由信息，calico 采用的是 <a href="https://en.wikipedia.org/wiki/Border_Gateway_Protocol" target="_blank" rel="noopener">BGP 路由协议</a>，全称是 <code>Border Gateway Protocol</code>。</p>
<p>除了能用于 docker 这样的容器外，它还能集成到容器集群平台 kubernetes、共有云平台 AWS、GCE 等， 而且也能很容易地集成到 openstack 等 Iaas 平台。</p>
<p>这篇文章就介绍 calico 是如何实现 docker 跨主机网络的。</p>
<h2 id="calico-集群安装和实验"><a href="#calico-集群安装和实验" class="headerlink" title="calico 集群安装和实验"></a>calico 集群安装和实验</h2><p>这部分我会在自己的 virtualbox 环境中运行多节点 docker，并使用 calico 实现跨主机的容器网络通信功能。实验环境一共启动了三台 centos7 虚拟机：</p>
<ul>
<li><code>node00</code>: 172.17.8.100</li>
<li><code>node01</code>: 172.17.8.101</li>
<li><code>node02</code>: 172.17.8.102</li>
</ul>
<p>这三台机器可以通过上面的 IP 地址进行通信，并且<strong>有不同的 hostname</strong>，推荐使用 vagrant 运行虚拟机集群。</p>
<p>这部分我们会手动安装 calico 集群，以加深理解，在生产环境中推荐使用自动化安装。</p>
<h3 id="1-安装-docker"><a href="#1-安装-docker" class="headerlink" title="1. 安装 docker"></a>1. 安装 docker</h3><p>既然要在 docker 集群中测试 calico 网络，当然要有一个能正常工作的 docker 环境。docker 的安装这里就不说了，请参考<a href="https://docs.docker.com/engine/installation/" target="_blank" rel="noopener">官网上的安装手册</a>选择适合自己的方式。</p>
<h3 id="2-安装-etcd"><a href="#2-安装-etcd" class="headerlink" title="2. 安装 etcd"></a>2. 安装 etcd</h3><p>calico 集群的信息需要保存在 etcd 中，因此我们首先要安装 etcd 服务，关于 etcd 的安装可以参考我<a href="http://cizixs.com/2016/08/02/intro-to-etcd">之前的文章</a>或者 etcd 官方网站。</p>
<p>因为是用来测试，所以我创建了一个单点的 etcd 集群。</p>
<h3 id="3-配置安装-docker-参数"><a href="#3-配置安装-docker-参数" class="headerlink" title="3. 配置安装 docker 参数"></a>3. 配置安装 docker 参数</h3><p>要想让 docker 支持多节点网络，需要添加 <code>cluster-store</code> 参数，修改 <code>/etc/docker/daemon.json</code> 文件（如果文件不存在需要创建），添加一行内容：</p>
<pre><code>{
  &quot;cluster-store&quot;: &quot;etcd://172.17.8.100:2379&quot;
}
</code></pre><p>然后重启 docker 服务，比如 <code>systemctl restart docker</code>，保证 docker 正常运行。</p>
<h3 id="4-下载-calicoctl-命令行"><a href="#4-下载-calicoctl-命令行" class="headerlink" title="4. 下载 calicoctl 命令行"></a>4. 下载 calicoctl 命令行</h3><p>calico 提供的 <code>calicoctl</code> 命令行工具能简化安装的过程，所以我们需要先下载这个程序：</p>
<pre><code>[~]# wget -O /usr/local/bin/calicoctl https://github.com/projectcalico/calicoctl/releases/download/v1.6.1/calicoctl
[~]# chmod +x /usr/local/bin/calicoctl
</code></pre><p>上述命令下载的是 1.6.1 版本，如果需要其他版本请按照<a href="https://github.com/projectcalico/calicoctl/releases" target="_blank" rel="noopener">官方指导</a>下载。</p>
<h3 id="5-配置-calicoctl-文件"><a href="#5-配置-calicoctl-文件" class="headerlink" title="5. 配置 calicoctl 文件"></a>5. 配置 calicoctl 文件</h3><p>运行的 calico 需要和 etcd 进行交互，因此要事先配置 etcd 的地址以便 calicoctl 使用。calicoctl 有一个配置文件 <code>/etc/calico/calicoctl.cfg</code>，往里面写入如下内容，etcd 地址根据需求更改：</p>
<pre><code># cat /etc/calico/calicoctl.cfg 
apiVersion: v1
kind: calicoApiConfig
metadata:
spec:
  datastoreType: &quot;etcdv2&quot;
  etcdEndpoints: &quot;http://172.17.8.100:2379&quot;
</code></pre><h3 id="6-运行-calico-节点容器"><a href="#6-运行-calico-节点容器" class="headerlink" title="6. 运行 calico 节点容器"></a>6. 运行 calico 节点容器</h3><p>calicoctl 会运行一个 docker 容器来运行 calico，容器镜像默认放在 <code>quay.io/calico/node:latest</code> 上面，在国内需要代理访问，也可以自行创建维护镜像或者事先下载好，这样的话就要把容器镜像指向自己维护的版本：</p>
<pre><code>[root@localhost ~]# calicoctl node run --ip=172.17.8.101 --name node01 --node-image 172.16.1.41:5000/calico/node:v2.6.0
Running command to load modules: modprobe -a xt_set ip6_tables
Enabling IPv4 forwarding
Enabling IPv6 forwarding
Increasing conntrack limit
Removing old calico-node container (if running).
Running the following command to start calico-node:

docker run --net=host --privileged --name=calico-node -d --restart=always -e CALICO_LIBNETWORK_ENABLED=true -e IP=172.17.8.101 -e ETCD_ENDPOINTS=http://172.17.8.100:2379 -e NODENAME=node01 -e CALICO_NETWORKING_BACKEND=bird -v /var/log/calico:/var/log/calico -v /var/run/calico:/var/run/calico -v /lib/modules:/lib/modules -v /run:/run -v /run/docker/plugins:/run/docker/plugins -v /var/run/docker.sock:/var/run/docker.sock 172.16.1.41:5000/calico/node:v2.6.0

Image may take a short time to download if it is not available locally.
Container started, checking progress logs.

Skipping datastore connection test
Using IPv4 address from environment: IP=172.17.8.101
IPv4 address 172.17.8.101 discovered on interface enp0s8
No AS number configured on node resource, using global value
Created default IPv4 pool (192.168.0.0/16) with NAT outgoing true. IPIP mode: off
Created default IPv6 pool (fd80:24e2:f998:72d6::/64) with NAT outgoing false. IPIP mode: off
Using node name: node01
Starting libnetwork service
Calico node started successfully
</code></pre><p>运行的命令指定了三个参数：</p>
<ul>
<li><code>--ip</code>：集群内节点用来互相通信的 IP 地址，如果要多个网卡或者网卡有多个 ip 地址最好手动指定。calicoctl 默认会自动选择这个 IP 地址，要实现自动化可以参考它的 IP 选择配置</li>
<li><code>--name</code>：唯一标识该节点的字符串，如果没有提供会使用 hostname，因此<strong>务必要保证 hostname 的唯一性</strong></li>
<li><code>--node-image</code>：calico node 的镜像地址，默认会从 <code>quay.io</code> 下载最新版本，如果想使用特定版本或者其他地址的镜像，需要手动指定</li>
</ul>
<p>从命令的输出可以看到，calicoctl 在运行容器之前还做了很多初始化的工作，比如加载需要的模块、配置系统参数、删除已经运行的 calico 容器（如果存在的话）；然后还会打印出来要运行的容器命令，所以理论上也可以手动执行这个命令；最后是运行使用的参数说明。</p>
<h3 id="7-创建网络并测试连通性"><a href="#7-创建网络并测试连通性" class="headerlink" title="7. 创建网络并测试连通性"></a>7. 创建网络并测试连通性</h3><p>在每个节点运行都不部署 calico 容器之后，calico 网络集群就搭建好了。接下来我们会创建两个网络，并测试 calico 跨主机网络的连通性，最终的网络示意图如下：</p>
<p><img src="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79gy1fkgfg04nwbj31hc0u0qb0.jpg" alt=""></p>
<p>图中只展示了两个节点，每个节点有两个容器，其中蓝色容器在同一个网络，红色容器在另外一个网络。</p>
<p>先创建两个网络：</p>
<pre><code># docker network create --driver calico --ipam-driver calico-ipam net1
# docker network create --driver calico --ipam-driver calico-ipam net2
</code></pre><p>docker 创建网络的时候，会调用 calico 的网络驱动，由驱动完成具体的工作。注意这个网络是跨主机的，因此无论在哪台机器创建，在其他机器上都能看到：</p>
<pre><code>[root@node01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
ea7007efb6d1        bridge              bridge              local
f76e9fe0eacc        host                host                local
c9bc43f8c601        net1                calico              global
ecda22cb8142        net2                calico              global
</code></pre><p>然后分别在网络中运行容器：</p>
<p>node00:</p>
<pre><code># docker run --net net1 --name containerA -tid busybox
# docker run --net net2 --name containerB -tid busybox
</code></pre><p>node01：</p>
<pre><code># docker run --net net1 --name containerC -tid busybox
# docker run --net net2 --name containerD -tid busybox
</code></pre><p>可以测试 containerA 和 containerC 能互相通信，containerB 和 containerD 能互相通信：</p>
<pre><code>[root@node00 ~]# docker exec -it containerA ping -c 3 containerC
PING containerC (192.168.196.129): 56 data bytes
64 bytes from 192.168.196.129: seq=0 ttl=62 time=50.587 ms
64 bytes from 192.168.196.129: seq=1 ttl=62 time=50.921 ms
64 bytes from 192.168.196.129: seq=2 ttl=62 time=51.688 ms

--- containerC ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 50.587/51.065/51.688 ms
</code></pre><p>同一个网络 docker 会保存各自的名字和 IP 的对应关系，而不同网络的容器无法解析，而且不能相互通信：</p>
<pre><code>[root@node00 ~]# docker exec -it containerA ping -c 3 192.168.196.128
PING 192.168.196.128 (192.168.196.128): 56 data bytes

--- 192.168.196.128 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
</code></pre><h2 id="报文流程"><a href="#报文流程" class="headerlink" title="报文流程"></a>报文流程</h2><p>我们来分析同个网络不同节点的容器是怎么通信的，借此还原 calico 的实现原理。以 containerA ping containerC 为例，先进入 containerA 中查看它的网络配置和路由表：</p>
<pre><code>[root@node00 ~]# docker exec -it containerA sh
/ # ip addr
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
5: cali0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue 
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff
    inet 192.168.18.64/32 scope global cali0
       valid_lft forever preferred_lft forever
</code></pre><p>可以看到 containerA 的 ip 地址为 <code>192.168.18.64/32</code>，需要注意的是它的 MAC 地址为 <code>ee:ee:ee:ee:ee:ee</code>，很明显是个固定的特殊地址（事实上所有 calico 生成的容器 MAC 地址都一样），这么做的是因为 calico 只关心三层的 IP 地址，根本不关心二层 MAC 地址。为什么这么说？等我们分析完，你就知道了。</p>
<p>要 ping 的目的地址为 <code>192.168.196.129/32</code>，两者不再同一个网络中，所以会查看路由获取下一跳的地址：</p>
<pre><code>/ # ip route
default via 169.254.1.1 dev cali0 
169.254.1.1 dev cali0 
</code></pre><p>容器的路由表非常有趣，和一般服务器创建的规则不同，所有的报文都会经过 <code>cali0</code> 发送到下一跳 <code>169.254.1.1</code>（这是预留的本地 IP 网段），这是 calico 为了简化网络配置做的选择，容器里的路由规则都是一样的，不需要动态更新。知道下一跳之后，容器会查询下一跳 <code>168.254.1.1</code> 的 MAC 地址，这个 ARP 请求发到哪里了呢？要回答这个问题，就要知道 <code>cali0</code> 是 veth pair 的一端，其对端是主机上 <code>caliXXXX</code> 命名的 interface，可以通过 <code>ethtool -S cali0</code> 列出对端的 interface idnex。</p>
<pre><code># ethtool -S cali0
NIC statistics:
     peer_ifindex: 6
</code></pre><p>而主机上 index 为 6 的 interface 为：</p>
<pre><code># ip addr
6: calif24874aae57: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP 
    link/ether a2:ff:0a:99:57:d2 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::a0ff:aff:fe99:57d2/64 scope link 
       valid_lft forever preferred_lft forever
</code></pre><p>报文会发送到这个 interface，这个 interface 有一个随机分配的 MAC 地址，但是没有<br>IP地址，接收到想要 <code>169.254.1.1</code> MAC 地址的 ARP 请求报文，它会怎么做呢？这个又不是它的 IP，而且它又没有和任何的 bridge 相连可以广播 ARP 报文。</p>
<p>只能抓包看看了，记住要先删除容器中 <code>169.254.1.1</code> 对应的 ARP 表项（使用 <code>ip neigh del</code> 命令），然后运行 ping 的时候在主机上抓包：</p>
<pre><code>[root@node00 ~]# tcpdump -nn -i calif24874aae57 -e
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on calif24874aae57, link-type EN10MB (Ethernet), capture size 262144 bytes
13:54:28.280252 ee:ee:ee:ee:ee:ee &gt; ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 169.254.1.1 tell 192.168.18.64, length 28
13:54:28.280274 a2:ff:0a:99:57:d2 &gt; ee:ee:ee:ee:ee:ee, ethertype ARP (0x0806), length 42: Reply 169.254.1.1 is-at a2:ff:0a:99:57:d2, length 28
13:54:28.280280 ee:ee:ee:ee:ee:ee &gt; a2:ff:0a:99:57:d2, ethertype IPv4 (0x0800), length 98: 192.168.18.64 &gt; 192.168.196.129: ICMP echo request, id 25581, seq 1, length 64
13:54:28.280669 a2:ff:0a:99:57:d2 &gt; ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 98: 192.168.196.129 &gt; 192.168.18.64: ICMP echo reply, id 25581, seq 1, length 64
</code></pre><p>从前面两个报文可以看到，接收到 ARP 请求后，它直接进行了应答，应答报文中 MAC 地址是 <code>a2:ff:0a:99:57:d2</code>，这正是该 interface 自己的 MAC 地址。换句话说，它把自己的 MAC 地址作为应答返回给容器。容器的后续报文 IP 地址还是目的容器，但是 MAC 地址就变成了主机上该 interface 的地址，也就是说所有的报文都会发给主机，然后主机根据 IP 地址进行转发。</p>
<p>主机这个 interface 不管 ARP 请求的内容，直接用自己的 MAC 地址作为应答的行为被成为 <code>ARP proxy</code>，是 calico 开启的，可以通过下面的命令确认：</p>
<pre><code># cat /proc/sys/net/ipv4/conf/calif24874aae57/proxy_arp
1
</code></pre><p>总的来说，可以认为 calico 把主机作为容器的默认网关来使用，所有的报文发到主机，然后主机根据路由表进行转发。和经典的网络架构不同的是，calico 并没有给默认网络配置一个 IP 地址（这样每个网络都会额外消耗一个 IP 资源，而且主机上也会增加对应的 IP 地址和路由信息），而是通过 arp proxy 和修改容器路由表来实现。</p>
<p>主机的 interface 接收到报文之后，下面的事情就容易理解了，所有的报文会根据路由表来走：</p>
<pre><code>[root@node00 ~]# ip route
169.254.0.0/16 dev enp0s3  scope link  metric 1002 
169.254.0.0/16 dev enp0s8  scope link  metric 1003 
192.168.18.64 dev calif24874aae57  scope link 
blackhole 192.168.18.64/26  proto bird 
192.168.18.65 dev cali4e5ed993aed  scope link 
192.168.196.128/26 via 172.17.8.101 dev enp0s8  proto bird 
</code></pre><p>而我们的 ping 报文目的地址是 <code>192.168.196.129</code>，匹配的是最后一个表项，把 <code>172.17.8.101</code> 作为下一跳地址，并通过 <code>enp0s8</code> 发出去。这个路由规则匹配的是一个网段，也就是说该网段所有的容器 IP 都在目的主机上，可以推测 calico 为每个主机默认分配了一段子网。</p>
<p><strong>NOTE</strong>：在发送到另一台主机之前，报文还会经过 iptables，calico 设置的 ACL 规则还会过滤报文。这个步骤暂时先跳过，我们先认为报文能够被继续转发。</p>
<p>报文到达容器所在的主机 <code>172.17.8.101</code>，下一步怎么走呢？当然是看路由器（这里还是跳过 iptables 的检查步骤）：</p>
<pre><code>[root@node01 ~]# ip route
169.254.0.0/16 dev enp0s3  scope link  metric 1002 
169.254.0.0/16 dev enp0s8  scope link  metric 1003 
192.168.18.64/26 via 172.17.8.100 dev enp0s8  proto bird 
192.168.196.128 dev cali4907e793262  scope link 
blackhole 192.168.196.128/26  proto bird 
192.168.196.129 dev cali69b2b8c106c  scope link 
</code></pre><p>同样的，这个报文会匹配最后一个路由规则，这个规则匹配的是一个 IP 地址，而不是网段，也就是说主机上每个容器都会有一个对应的路由表项。报文发送到 <code>cali69b2b8c106c</code> 这个 veth pair，然后从另一端发送给容器，容器接收到报文之后，发送目的地址是自己，就做出 ping 应答，应答报文的返回路径和之前类似。</p>
<p>总体的报文路径就是按照下图中的数字顺序，回来的报文按照原路返回：</p>
<p><img src="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79gy1fkgfhzbl9kj31hc0u047e.jpg" alt="calico-packet-flow"></p>
<h2 id="组件和架构"><a href="#组件和架构" class="headerlink" title="组件和架构"></a>组件和架构</h2><p>看完 calico 的报文流程，大致也能分析出 calico 做的事情：</p>
<ul>
<li>分配和管理 IP</li>
<li>配置上容器的 veth pair 和容器内默认路由</li>
<li>根据集群网络情况实时更新节点上路由表</li>
</ul>
<p>从部署过程可以知道，除了 etcd 保存了数据之外，节点上也就只运行了一个 calico-node 的容器，所以推测是这个容器实现了上面所有的功能。calico/node 这个容器运行了多个组件：</p>
<pre><code>[root@node00 ~]# docker exec -it calico-node sh
/ # ps aux
PID   USER     TIME   COMMAND
    1 root       0:01 /sbin/runsvdir -P /etc/service/enabled
   75 root       0:00 runsv felix
   76 root       0:00 runsv bird
   77 root       0:00 runsv bird6
   78 root       0:00 runsv confd
   79 root       0:00 runsv libnetwork
   80 root       0:02 svlogd /var/log/calico/felix
   81 root      30:49 calico-felix
   82 root       0:00 svlogd /var/log/calico/confd
   83 root       0:05 confd -confdir=/etc/calico/confd -interval=5 -watch --log-level=debug -node=http://172.17.8.100:2379 -client-key= -client-cert= -client-ca-keys=
   84 root       0:00 svlogd -tt /var/log/calico/bird
   85 root       0:20 bird -R -s /var/run/calico/bird.ctl -d -c /etc/calico/confd/config/bird.cfg
   86 root       0:00 svlogd -tt /var/log/calico/bird6
   87 root       0:18 bird6 -R -s /var/run/calico/bird6.ctl -d -c /etc/calico/confd/config/bird6.cfg
   94 root       0:00 svlogd /var/log/calico/libnetwork
   95 root       0:04 libnetwork-plugin
</code></pre><p><a href="http://smarden.org/runit/runsv.8.html" target="_blank" rel="noopener">runsv</a> 是一个 minimal 的 init 系统提供的命令，用来管理多个进程，可以看到它运行的进程包括：<code>felix</code>、<code>bird</code>、<code>bird6</code>、<code>confd</code> 和 <code>libnetwork</code>，这部分就介绍各个进程的功能。</p>
<h3 id="libnetwork-plugin"><a href="#libnetwork-plugin" class="headerlink" title="libnetwork plugin"></a>libnetwork plugin</h3><p><a href="https://github.com/projectcalico/libnetwork-plugin" target="_blank" rel="noopener">libnetwork-plugin</a> 是 calico 提供的 docker 网络插件，主要提供的是 IP 管理和网络管理的功能。</p>
<p>默认情况下，当网络中出现第一个容器时，calico 会为容器所在的节点分配一段子网（子网掩码为 <code>/26</code>，比如<code>192.168.196.128/26</code>），后续出现在该节点上的容器都从这个子网中分配 IP 地址。这样做的好处是能够缩减节点上的路由表的规模，按照这种方式节点上 <code>2^6 = 64</code> 个 IP 地址只需要一个路由表项就行，而不是为每个 IP 单独创建一个路由表项。节点上创建的子网段可以在etcd 中 <code>/calico/ipam/v2/host/&lt;node_name&gt;/ipv4/block/</code> 看到。</p>
<p>calico 还允许创建容器的时候指定 IP 地址，如果用户指定的 IP 地址不在节点分配的子网段中，calico 会专门为该地址添加一个 <code>/32</code> 的网段。</p>
<h3 id="BIRD"><a href="#BIRD" class="headerlink" title="BIRD"></a>BIRD</h3><p><a href="http://bird.network.cz/" target="_blank" rel="noopener">BIRD</a>（BIRD Internet Routing Daemon） 是一个常用的网络路由软件，支持很多路由协议（BGP、RIP、OSPF等），calico 用它在节点之间共享路由信息。</p>
<p>关于 BIRD 如何配置 BGP 协议，可以参考<a href="http://bird.network.cz/?get_doc&amp;f=bird-6.html#ss6.3" target="_blank" rel="noopener">官方文档</a>，对应的配置文件在 <code>/etc/calico/confd/config/</code> 目录。</p>
<p><strong>NOTE</strong>：至于为什么选择 BGP 协议而不是其他的路由协议，官网上也有介绍: <a href="https://www.projectcalico.org/why-bgp/" target="_blank" rel="noopener">Why BGP?</a></p>
<p>默认所有的节点使用相同的 AS number 64512，因为 AS number 是一个32 比特的字段，所以有效取值范围是 <code>[0-4294967295]</code>，可以通过 <code>calicoctl config get asNumber</code> 命令查看当前节点使用的 AS number。</p>
<p>默认情况下，每个 calico 节点会和集群中其他所有节点建立 BGP peer 连接，也就是说这是一个 O(n^2) 的增长趋势。在集群规模比较小的情况下，这种模式是可以接受的，但是当集群规模扩展到百个节点、甚至更多的时候，这样的连接数无疑会带来很大的负担。为了解决集群规模较大情况下 BGP client 连接数膨胀的问题，calico 引入了 RR（Router Reflector） 的功能。</p>
<p>RR 的基本思想是选择一部分节点（一个或者多个）作为 Global BGP Peer，它们和所有的其他节点互联来交换路由信息，其他的节点只需要和 Global BGP Peer 相连就行，不需要之间再两两连接。更多的组网模式也是支持的，不管怎么组网，最核心的思想就是所有的节点能获取到整个集群的路由信息。</p>
<p>calico 对 BGP 的使用还是相对简单的，BGP 协议的原理不是一两句话能解释清楚的，以后有机会单独写篇文章来说吧。</p>
<h3 id="confd"><a href="#confd" class="headerlink" title="confd"></a>confd</h3><p>因为 bird 的配置文件会根据用户设置的变化而变化，因此需要一种动态的机制来实时维护配置文件并通知 bird 使用最新的配置，这就是 confd 的工作。<code>confd</code> 监听 etcd 的数据，用来更新 bird 的配置文件，并重新启动 bird 进程让它加载最新的配置文件。<code>confd</code> 的工作目录是  <code>/etc/calico/confd</code>，里面有三个目录：</p>
<ul>
<li><code>conf.d</code>：<code>confd</code> 需要读取的配置文件，每个配置文件告诉 confd 模板文件在什么，最终生成的文件应该放在什么地方，更新时要执行哪些操作等</li>
<li><code>config</code>：生成的配置文件最终放的目录</li>
<li><code>templates</code>：模板文件，里面包括了很多变量占位符，最终会替换成 etcd 中具体的数据</li>
</ul>
<p>具体的配置文件很多，我们只看一个例子：</p>
<pre><code>/ # cat /etc/calico/confd/conf.d/bird.toml
[template]
src = &quot;bird.cfg.mesh.template&quot;
dest = &quot;/etc/calico/confd/config/bird.cfg&quot;
prefix = &quot;/calico/bgp/v1&quot;
keys = [
    &quot;/host&quot;,
    &quot;/global&quot;
]
check_cmd = &quot;bird -p -c {{.src}}&quot;
reload_cmd = &quot;pkill -HUP bird || true&quot;
</code></pre><p>它会监听 etcd 的 <code>/calico/bgp/v1</code> 路径，一旦发现更新，就用其中的内容更新模板文件 <code>bird.cfg.mesh.template</code>，把新生成的文件放在 <code>/etc/calico/confd/config/bird.cfg</code>，文件改变之后还会运行 <code>reload_cmd</code> 指定的命令重启 bird 程序。</p>
<p><strong>NOTE</strong>：关于 confd 的使用和工作原理请参考<a href="https://github.com/kelseyhightower/confd" target="_blank" rel="noopener">它的官方 repo</a>。</p>
<h3 id="felix"><a href="#felix" class="headerlink" title="felix"></a>felix</h3><p>felix 负责最终网络相关的配置，也就是容器网络在 linux 上的配置工作，比如：</p>
<ul>
<li>更新节点上的路由表项</li>
<li>更新节点上的 iptables 表项</li>
</ul>
<p>它的主要工作是从 etcd 中读取网络的配置，然后根据配置更新节点的路由和 iptables，felix 的代码在 <a href="https://github.com/projectcalico/felix" target="_blank" rel="noopener">github projectcalico/felix</a>。</p>
<h3 id="etcd"><a href="#etcd" class="headerlink" title="etcd"></a>etcd</h3><p>etcd 已经在前面多次提到过，它是一个分布式的键值存储数据库，保存了 calico 网络元数据，用来协调 calico 网络多个节点。可以使用 etcdctl 命令行来读取 calico 在 etcd 中保存的数据：</p>
<pre><code># etcdctl -C 172.17.8.100:2379 ls /calico
/calico/ipam
/calico/v1
/calico/bgp
</code></pre><p>每个目录保存的数据大致功能如下：</p>
<ul>
<li><code>/calico/ipam</code>：IP 地址分配管理，保存了节点上分配的各个子网段以及网段中 IP 地址的分配情况</li>
<li><code>/calico/v1</code>：profile 和 policy 的配置信息，节点上运行的容器 endpoint 信息（IP 地址、veth pair interface 的名字等），</li>
<li><code>/calico/bgp</code>：和 BGP 相关的信息，包括 mesh 是否开启，每个节点作为 gateway 通信的 IP 地址，AS number 等</li>
</ul>
<h2 id="强大的防火墙功能"><a href="#强大的防火墙功能" class="headerlink" title="强大的防火墙功能"></a>强大的防火墙功能</h2><p>从前面的实验我们不仅知道了 calico 容器网络的报文流程是怎样的，还发现了一个事实：<strong>默认情况下，同一个网络的容器能通信（不管容器是不是在同一个主机上），不同网络的容器是无法通信的。</strong></p>
<p>这个行为是 calico 强大的防火墙实现的，默认情况下 calico 为每个网络创建一个 profile：</p>
<pre><code>[root@node01 ~]# calicoctl get profile net2 -o yaml
- apiVersion: v1
  kind: profile
  metadata:
    name: net2
    tags:
    - net2
  spec:
    egress:
    - action: allow
      destination: {}
      source: {}
    ingress:
    - action: allow
      destination: {}
      source:
        tag: net2
</code></pre><ul>
<li>profile 是和网络对应的，比如上面 <code>metadata.name</code> 的值是 <code>net2</code>，代表它匹配 <code>net2</code> 网络，并应用到所有的 <code>net2</code> 网络容器中</li>
<li>calico 使用 label 来增加防火墙规则的灵活性，源地址和目的地址都可以通过 label 匹配</li>
<li>profile 中 <code>metadata.tags</code> 会应用到网络中所有的容器上</li>
<li>如果有定义，profile中的 <code>metadata.labels</code> 也会应用到网络中所有的容器上</li>
<li>spec 指定 profile 默认的网络规则，egress 没有限制，ingress 表示只运行 tag 为 net2 容器（也就是同一个网络的容器）的访问</li>
</ul>
<p>每一个加入到网络的容器都会加上这个 profile，以此来实现网络之间的隔离。可以通过查看 endpoints 的详情得到它上面绑定的 <code>profiles</code>：</p>
<pre><code>[root@node01 ~]# calicoctl get workloadEndpoint 4e5ed993aed9e7c89bd5514fa67a2a8346295238801974d77eac8b444ae2afb0 -o yaml
- apiVersion: v1
  kind: workloadEndpoint
  metadata:
    name: 4e5ed993aed9e7c89bd5514fa67a2a8346295238801974d77eac8b444ae2afb0
    node: node00
    orchestrator: libnetwork
    workload: libnetwork
  spec:
    interfaceName: cali4e5ed993aed
    ipNetworks:
    - 192.168.18.65/32
    mac: ee:ee:ee:ee:ee:ee
    profiles:
    - net2
</code></pre><p>用户也可以根据需求修改 profile 和 policy，可以参考<a href="https://docs.projectcalico.org/v2.6/getting-started/docker/tutorials/security-using-calico-profiles-and-policy" target="_blank" rel="noopener">官方教程</a>。</p>
<p>不过上面的防火墙都是针对网络的（网络中的容器的规则都是相同的），不能精细化到容器，也就是说只能做到网络之间的隔离和连通。不过 calico 也提供了对容器级别防火墙的支持，它主要是借助 docker 容器上的 label，通过匹配这些键值对来精细化控制防火墙。启动 docker label 支持需要在 <code>calicoctl node run</code> 命令运行时加上 <code>--use-docker-networking-container-labels</code> 参数，而且一旦启用后原来的 profile 就被废弃不能用了（可以用纯 policy 实现原来的 profile 功能）。容器启动的时候需要添加上 label 用来作为 policy 的标识，比如 <code>--label org.projectcalico.label.role=frontend</code>，具体的使用案例请参考<a href="https://docs.projectcalico.org/v2.6/getting-started/docker/tutorials/security-using-docker-labels-and-calico-policy" target="_blank" rel="noopener">这个教程</a>。</p>
<p>如果只要提供网络之间的隔离，可以使用 profile 和 policy；如果要实现精细化的容器之间的隔离，就需要启用容器的 label 功能了。在底层，calico 的 flelix 组件会实时跟踪 profile 和 policy 的内容，并更新各个节点的 iptables。</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>calico 的核心是通过维护路由规则实现容器的通信，路由信息的传播是 BIRD 软件通过 BGP 协议完成的，而节点上路由和防火墙规则是 felix 维护的。</p>
<p>从 calico 本身的特性来说，它没有办法实现 VPC 网络，并且需要维护大量的路由表项和 iptables 表项，如果要部署在规模很大的生产环境中，需要预先规划系统的 iptables 和路由表项的上限。</p>
<p>在我看来，calico 最大的优点有两个：直接三层互联的网络，不需要报文封装，因此性能更好而且能和原来的网络设施直接融合；强大的防火墙规则，利用 label 机制灵活地匹配容器，几乎可以设置任何需求的防火墙。</p>
<p>但 calico 并非没有缺点，首先是它引入了 BGP 协议，虽然 bird 的配置很简单，但是运维这个系统需要熟悉 BGP 协议，这无疑会增加了人力、时间和金钱方面的投入；其次，calico 能支持的网络规模也有上限，虽然可以通过 Router Reflector 来缓解，但这么做又大大增加了网络规划、使用和排查的复杂度；最后 calico 无法用来实现 VPC 网络，IP 地址空间是所有租户共享的，租户之间是通过防火墙隔离的。</p>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li><a href="http://www.lijiaocn.com/%E9%A1%B9%E7%9B%AE/2017/04/11/calico-usage.html" target="_blank" rel="noopener">Calico网络的原理、组网方式与使用</a></li>
<li><a href="http://leebriggs.co.uk/blog/2017/02/18/kubernetes-networking-calico.html" target="_blank" rel="noopener">Kubernetes Networking: Part 2 - Calico</a></li>
<li><a href="https://docs.projectcalico.org/v2.6/usage/troubleshooting/faq" target="_blank" rel="noopener">calico: Frequently Asked Questions</a></li>
</ul>

                </div>
            </section>
        </article>
    </div>
    
<nav class="pagination">
    
    
    <a class="prev-post" title="使用 tc netem 模拟网络异常" href="/2017/10/23/tc-netem-for-terrible-network/">
        ← 使用 tc netem 模拟网络异常
    </a>
    
    <span class="prev-next-post">•</span>
    
    <a class="next-post" title="linux 上实现 vxlan 网络" href="/2017/09/28/linux-vxlan/">
        linux 上实现 vxlan 网络 →
    </a>
    
    
</nav>

    <div class="inner">
    <!-- Begin Mailchimp Signup Form -->
    <link href="//cdn-images.mailchimp.com/embedcode/classic-10_7.css" rel="stylesheet" type="text/css">
    <style type="text/css">
    	#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
    	/* Add your own Mailchimp form style overrides in your site stylesheet or in this style block.
    	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
    </style>
    <div id="mc_embed_signup">
    <form action="https://cizixs.us7.list-manage.com/subscribe/post?u=2d561b8dea52d73a2e05e6dcb&amp;id=5c710f135b" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
        <div id="mc_embed_signup_scroll">
    	<h2>订阅本博客，第一时间收到文章更新</h2>
    <div class="indicates-required"><span class="asterisk">*</span> indicates required</div>
    <div class="mc-field-group">
    	<label for="mce-EMAIL">邮件地址  <span class="asterisk">*</span>
    </label>
    	<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
    </div>
    	<div id="mce-responses" class="clear">
    		<div class="response" id="mce-error-response" style="display:none"></div>
    		<div class="response" id="mce-success-response" style="display:none"></div>
    	</div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
        <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_2d561b8dea52d73a2e05e6dcb_5c710f135b" tabindex="-1" value=""></div>
        <div class="clear"><input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
        </div>
    </form>
    </div>
    <script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';}(jQuery));var $mcj = jQuery.noConflict(true);</script>
    <!--End mc_embed_signup-->
    </div>

    <div class="inner">
        <div id="disqus_thread"></div>
    </div>

    
</main>

<div class="t-g-control">
    <div class="gotop">
        <svg class="icon" width="32px" height="32px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M793.024 710.272a32 32 0 1 0 45.952-44.544l-310.304-320a32 32 0 0 0-46.4 0.48l-297.696 320a32 32 0 0 0 46.848 43.584l274.752-295.328 286.848 295.808z" fill="#8a8a8a" /></svg>
    </div>
    <div class="toc-control">
        <svg class="icon toc-icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M779.776 480h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M779.776 672h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M256 288a32 32 0 1 0 0 64 32 32 0 0 0 0-64M392.576 352h387.2a32 32 0 0 0 0-64h-387.2a32 32 0 0 0 0 64M256 480a32 32 0 1 0 0 64 32 32 0 0 0 0-64M256 672a32 32 0 1 0 0 64 32 32 0 0 0 0-64" fill="#8a8a8a" /></svg>
        <svg class="icon toc-close" style="display: none;" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M512 960c-247.039484 0-448-200.960516-448-448S264.960516 64 512 64 960 264.960516 960 512 759.039484 960 512 960zM512 128.287273c-211.584464 0-383.712727 172.128262-383.712727 383.712727 0 211.551781 172.128262 383.712727 383.712727 383.712727 211.551781 0 383.712727-172.159226 383.712727-383.712727C895.712727 300.415536 723.551781 128.287273 512 128.287273z" fill="#8a8a8a" /><path d="M557.05545 513.376159l138.367639-136.864185c12.576374-12.416396 12.672705-32.671738 0.25631-45.248112s-32.704421-12.672705-45.248112-0.25631l-138.560301 137.024163-136.447897-136.864185c-12.512727-12.512727-32.735385-12.576374-45.248112-0.063647-12.512727 12.480043-12.54369 32.735385-0.063647 45.248112l136.255235 136.671523-137.376804 135.904314c-12.576374 12.447359-12.672705 32.671738-0.25631 45.248112 6.271845 6.335493 14.496116 9.504099 22.751351 9.504099 8.12794 0 16.25588-3.103239 22.496761-9.247789l137.567746-136.064292 138.687596 139.136568c6.240882 6.271845 14.432469 9.407768 22.65674 9.407768 8.191587 0 16.352211-3.135923 22.591372-9.34412 12.512727-12.480043 12.54369-32.704421 0.063647-45.248112L557.05545 513.376159z" fill="#8a8a8a" /></svg>
    </div>
    <div class="gobottom">
        <svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M231.424 346.208a32 32 0 0 0-46.848 43.584l297.696 320a32 32 0 0 0 46.4 0.48l310.304-320a32 32 0 1 0-45.952-44.544l-286.848 295.808-274.752-295.36z" fill="#8a8a8a" /></svg>
    </div>
</div>
<div class="toc-main" style="right: -100%">
    <div class="post-toc">
        <span>TOC</span>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#calico-简介"><span class="toc-text">calico 简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#calico-集群安装和实验"><span class="toc-text">calico 集群安装和实验</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-安装-docker"><span class="toc-text">1. 安装 docker</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-安装-etcd"><span class="toc-text">2. 安装 etcd</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-配置安装-docker-参数"><span class="toc-text">3. 配置安装 docker 参数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-下载-calicoctl-命令行"><span class="toc-text">4. 下载 calicoctl 命令行</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-配置-calicoctl-文件"><span class="toc-text">5. 配置 calicoctl 文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-运行-calico-节点容器"><span class="toc-text">6. 运行 calico 节点容器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-创建网络并测试连通性"><span class="toc-text">7. 创建网络并测试连通性</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#报文流程"><span class="toc-text">报文流程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#组件和架构"><span class="toc-text">组件和架构</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#libnetwork-plugin"><span class="toc-text">libnetwork plugin</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#BIRD"><span class="toc-text">BIRD</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#confd"><span class="toc-text">confd</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#felix"><span class="toc-text">felix</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#etcd"><span class="toc-text">etcd</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#强大的防火墙功能"><span class="toc-text">强大的防火墙功能</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#总结"><span class="toc-text">总结</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#参考资料"><span class="toc-text">参考资料</span></a></li></ol>
    </div>
</div>



        

<aside class="read-next outer">
    <div class="inner">
        <div class="read-next-feed">
            
            

<article class="read-next-card"  style="background-image: url(https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxcn9ft3j318w0txdo6.jpg)"  >
  <header class="read-next-card-header">
    <small class="read-next-card-header-sitetitle">&mdash; Cizixs Write Here &mdash;</small>
    <h3 class="read-next-card-header-title">Recent Posts</h3>
  </header>
  <div class="read-next-divider">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
      <path d="M13 14.5s2 3 5 3 5.5-2.463 5.5-5.5S21 6.5 18 6.5c-5 0-7 11-12 11C2.962 17.5.5 15.037.5 12S3 6.5 6 6.5s4.5 3.5 4.5 3.5"/>
    </svg>
  </div>
  <div class="read-next-card-content">
    <ul>
      
      
      
      <li>
        <a href="/2018/08/26/what-is-istio/">什么是 istio</a>
      </li>
      
      
      
      <li>
        <a href="/2018/08/25/knative-serverless-platform/">serverless 平台 knative 简介</a>
      </li>
      
      
      
      <li>
        <a href="/2018/06/25/kubernetes-resource-management/">kubernetes 资源管理概述</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/24/use-prometheus-and-grafana-to-monitor-linux-machine/">使用 promethues 和 grafana 监控自己的 linux 机器</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/13/linux-udp-packet-drop-debug/">linux 系统 UDP 丢包问题分析思路</a>
      </li>
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    </ul>
  </div>
  <footer class="read-next-card-footer">
    <a href="/archives">  MORE  → </a>
  </footer>
</article>


            
            
            
        </div>
    </div>
</aside>


<footer class="site-footer outer">

	<div class="site-footer-content inner">
		<section class="copyright">
			<a href="/" title="Cizixs Write Here">Cizixs Write Here</a>
			&copy; 2019
		</section>
		<nav class="site-footer-nav">
			
            <a href="https://hexo.io" title="Hexo" target="_blank" rel="noopener">Hexo</a>
            <a href="https://github.com/xzhih/hexo-theme-casper" title="Casper" target="_blank" rel="noopener">Casper</a>
        </nav>
    </div>
</footer>






<div class="floating-header" >
	<div class="floating-header-logo">
        <a href="/" title="Cizixs Write Here">
			
                <img src="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg" alt="Cizixs Write Here icon" />
			
            <span>Cizixs Write Here</span>
        </a>
    </div>
    <span class="floating-header-divider">&mdash;</span>
    <div class="floating-header-title">docker 容器网络方案：calico 网络模型</div>
    <progress class="progress" value="0">
        <div class="progress-container">
            <span class="progress-bar"></span>
        </div>
    </progress>
</div>
<script>
   $(document).ready(function () {
    var progressBar = document.querySelector('progress');
    var header = document.querySelector('.floating-header');
    var title = document.querySelector('.post-full-title');
    var lastScrollY = window.scrollY;
    var lastWindowHeight = window.innerHeight;
    var lastDocumentHeight = $(document).height();
    var ticking = false;

    function onScroll() {
        lastScrollY = window.scrollY;
        requestTick();
    }
    function requestTick() {
        if (!ticking) {
            requestAnimationFrame(update);
        }
        ticking = true;
    }
    function update() {
        var rect = title.getBoundingClientRect();
        var trigger = rect.top + window.scrollY;
        var triggerOffset = title.offsetHeight + 35;
        var progressMax = lastDocumentHeight - lastWindowHeight;
            // show/hide floating header
            if (lastScrollY >= trigger + triggerOffset) {
                header.classList.add('floating-active');
            } else {
                header.classList.remove('floating-active');
            }
            progressBar.setAttribute('max', progressMax);
            progressBar.setAttribute('value', lastScrollY);
            ticking = false;
        }

        window.addEventListener('scroll', onScroll, {passive: true});
        update();

        // TOC
        var width = $('.toc-main').width();
        $('.toc-control').click(function () {
            if ($('.t-g-control').css('width')=="50px") {
                if ($('.t-g-control').css('right')=="0px") {
                    $('.t-g-control').animate({right: width}, "slow");
                    $('.toc-main').animate({right: 0}, "slow");
                    toc_icon()
                } else {
                    $('.t-g-control').animate({right: 0}, "slow");
                    $('.toc-main').animate({right: -width}, "slow");
                    toc_icon()
                }
            } else {
                if ($('.toc-main').css('right')=="0px") {
                    $('.toc-main').slideToggle("fast", toc_icon());
                } else {
                    $('.toc-main').css('right', '0px');
                    toc_icon()
                }
            }
        })

        function toc_icon() {
            if ($('.toc-icon').css('display')=="none") {
                $('.toc-close').hide();
                $('.toc-icon').show();
            } else {
                $('.toc-icon').hide();
                $('.toc-close').show();
            }
        }

        $('.gotop').click(function(){
            $('html,body').animate({scrollTop:$('.post-full-header').offset().top}, 800);
        });
        $('.gobottom').click(function () {
            $('html,body').animate({scrollTop:$('.pagination').offset().top}, 800);
        });

        // highlight
        // https://highlightjs.org
        $('pre code').each(function(i, block) {
            hljs.highlightBlock(block);
        });
        $('td.code').each(function(i, block) {
            hljs.highlightBlock(block);
        });

        console.log("this theme is from https://github.com/xzhih/hexo-theme-casper")
    });
</script>



<link rel="stylesheet" href="https://cdn.staticfile.org/lightgallery/1.3.9/css/lightgallery.min.css">



<script src="https://cdn.staticfile.org/lightgallery/1.3.9/js/lightgallery.min.js"></script>


<script>
	$(function () {
		var postImg = $('#lightgallery').find('img');
		postImg.addClass('post-img');
		postImg.each(function () {
			var imgSrc = $(this).attr('src');
			$(this).attr('data-src', imgSrc);
		});
		$('#lightgallery').lightGallery({selector: '.post-img'});
	});
</script>



<script>

/**
*  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
*  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/

var disqus_config = function () {
this.page.url = 'http://cizixs.com/2017/10/19/docker-calico-network/';  // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = 'http://cizixs.com/2017/10/19/docker-calico-network/'; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};

(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://cizixs.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
                            


    </div>
</body>
</html>
